﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Controls;

using PlanningGIS.Util.Convertor;
using PlanningGIS.ArcGIS;
using PlanningGIS.Util.Log;
using PlanningGIS.Engine.Controls;

namespace PlanningGIS.DataCheck.model
{
    
    public class TerPtLnConfictCheck:Check
    {
        public override string ToString()
        {
            return "TerPtLnConfict";
        }

        /// <summary>
        /// 执行检查
        /// </summary>
        /// <param name="errType">错误描述</param>
        /// <param name="pFeatLyrPt">高程点图层</param>
        /// <param name="fieldNamePt">点图层高程字段</param>
        /// <param name="pFeatLyrLn">等高线图层</param>
        /// <param name="fieldNameLn">线图层高程字段</param>
        /// <param name="buffer">对高程点所开缓冲半径</param>
        /// <param name="extent">检查范围</param>
        /// <returns></returns>
        public int Check(string errType, IFeatureLayer pFeatLyrPt, string fieldNamePt,
            IFeatureLayer pFeatLyrLn, string fieldNameLn, double buffer, IGeometry extent)
        {
            int errCount = 0;

            IFeatureClass pFeatClsPt = pFeatLyrPt.FeatureClass;
            if (pFeatClsPt.ShapeType != esriGeometryType.esriGeometryPoint)
            {
                LogHelper.WriteLog("[" + pFeatLyrPt.Name + "]不是点图层，检查失败！");
                return -1;
            }

            IFeatureClass pFeatClsLn = pFeatLyrLn.FeatureClass;
            if (pFeatClsLn.ShapeType != esriGeometryType.esriGeometryPolyline)
            {
                LogHelper.WriteLog("[" + pFeatLyrLn.Name + "]不是线图层，检查失败！");
                return -1;
            }

            int idxPt = pFeatClsPt.FindField(fieldNamePt);
            if (idxPt == -1)
            {
                LogHelper.WriteLog("[" + pFeatLyrPt.Name + "]图层上[" + fieldNamePt + "]字段不存在，检查失败！");
                return -1;
            }

            int idxLn = pFeatClsLn.FindField(fieldNameLn);
            if (idxLn == -1)
            {
                LogHelper.WriteLog("[" + pFeatLyrLn.Name + "]图层上[" + fieldNameLn + "]字段不存在，检查失败！");
            }

            ISpatialFilter pSpatialFileter = new SpatialFilterClass();
            if (extent != null) pSpatialFileter.Geometry = extent;
            pSpatialFileter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
            pSpatialFileter.GeometryField = pFeatClsPt.ShapeFieldName;

            showFakePro(true);
            LogHelper.WriteLog("正在计算需要检查的要素数目...");

            int max = FeatureClassHelper.GetFeatureCountFromLayer(pFeatLyrPt, pSpatialFileter);// pFeatClsPt.FeatureCount(pSpatialFileter);

            LogHelper.WriteLog("计算完毕。共有" + max + "个要素参与检查。");
            showFakePro(false);

            setProcessBarMax(max);

            IFeatureCursor pFeatCurPt;
            pFeatCurPt = pFeatLyrPt.Search(pSpatialFileter, false);

            IFeature pFeatPt;
            pFeatPt = pFeatCurPt.NextFeature();
            int i = 0;
            while (pFeatPt != null)
            {
                IPoint pPoint = null;
                IPolyline pPolyline = null;
                IGeometry pBuffer = null;
                try
                {
                    setProcessBarCurrent(i++);
                    pPoint = pFeatPt.ShapeCopy as IPoint;
                    pBuffer = GeometryHelper.GetBuffer(pPoint, buffer, (pFeatClsPt as IGeoDataset).SpatialReference);

                    ISpatialFilter pSF = new SpatialFilterClass();
                    pSF.Geometry = pBuffer;
                    pSF.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                    pSF.GeometryField = pFeatClsLn.ShapeFieldName;

                    int count = pFeatClsLn.FeatureCount(pSF);
                    //如果在所给半径的缓冲区内找到的线要素少于两个，则该点无法做点线矛盾检查，故跳过
                    if (count < 2) goto NEXTFEATURE;

                    IPoint pPntUp = new PointClass();
                    pPntUp.PutCoords(pPoint.X, pPoint.Y + buffer);

                    IPoint pPntDown = new PointClass();
                    pPntDown.PutCoords(pPoint.X, pPoint.Y - buffer);

                    IPoint pPntLeft = new PointClass();
                    pPntLeft.PutCoords(pPoint.X - buffer, pPoint.Y);

                    IPoint pPntRight = new PointClass();
                    pPntRight.PutCoords(pPoint.X + buffer, pPoint.Y);

                    IPolyline pPolyline1 = new PolylineClass();
                    pPolyline1.FromPoint = pPntUp;
                    pPolyline1.ToPoint = pPntDown;

                    IPolyline pPolyline2 = new PolylineClass();
                    pPolyline2.FromPoint = pPntLeft;
                    pPolyline2.ToPoint = pPntRight;

                    #region 判断是画横线还是画纵线
                    IFeatureSelection pFeatSel = pFeatLyrLn as IFeatureSelection;
                    pFeatSel.SelectFeatures(pSF, esriSelectionResultEnum.esriSelectionResultNew, true);

                    IEnumIDs pIDs = pFeatSel.SelectionSet.IDs;
                    pIDs.Reset();
                    int id = pIDs.Next();
                    if (id == -1) continue;

                    IFeature pFeatTmp = pFeatClsLn.GetFeature(id);
                    ICurve pCurve = pFeatTmp.ShapeCopy as ICurve;

                    pFeatSel.Clear();

                    double distanceAlongCurve = 0;
                    double distanceFromCurve = 0;
                    bool bRightSide = false;

                    IPoint outPnt = null;
                    pCurve.QueryPointAndDistance(esriSegmentExtension.esriExtendAtFrom, pPoint, false, outPnt, ref distanceAlongCurve,
                        ref distanceFromCurve, ref bRightSide);


                    ILine pLine = new LineClass();
                    pCurve.QueryTangent(esriSegmentExtension.esriExtendAtFrom, distanceAlongCurve, false, buffer, pLine);

                    double angle;
                    angle = (180 * pLine.Angle) / Math.PI;
                    if (angle < 0) angle = angle + 360;
                    if (angle > 180) angle = angle - 180;
                    bool vors;
                    vors = (angle < 45 || angle > 135);

                    #endregion

                    FindConfict(errType, pFeatLyrPt, pFeatPt, idxPt, pFeatLyrLn, idxLn, vors ? pPolyline1 : pPolyline2, ref errCount);
                }
                catch (Exception ex)
                {
                   LogHelper.WriteErrLog("检查ID为[" + pFeatPt.OID + "]的要素失败：" + ex.Message);
                }
            NEXTFEATURE:
                DataCheckUtility.ReleaseComObject(pPoint);
                DataCheckUtility.ReleaseComObject(pBuffer);
                DataCheckUtility.ReleaseComObject(pPolyline);

                pFeatPt = pFeatCurPt.NextFeature();
            }

            finishPro();
            LogHelper.WriteLog("高程点和相邻的等高线之间点线矛盾检查结束。共发现" + errCount + "处错误！\n");
            DataCheckUtility.ReleaseComObject(pFeatCurPt);
            return errCount;
        }


        private bool FindConfict(string errType,IFeatureLayer pFeatLyrPt, IFeature pFeatPt,int idxPt, IFeatureLayer pFeatLyrLn,
            int idxLn, IPolyline pPolyline ,ref int errCount)
        {
            int idmore = -1;
            double more = 0;
            int idless = -1;
            double less = 0;
            IFeatureClass pFeatClsLn = pFeatLyrLn.FeatureClass ;

            ISpatialFilter pSpatialFileter = new SpatialFilterClass();
            pSpatialFileter.Geometry = pPolyline;
            pSpatialFileter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
            pSpatialFileter.GeometryField = pFeatClsLn.ShapeFieldName;

            IPoint pPoint = pFeatPt.ShapeCopy as IPoint;
            ITopologicalOperator2 pTop = pPolyline as ITopologicalOperator2;
            
            IFeatureCursor pFeatCurLn;
            pFeatCurLn = pFeatLyrLn.Search(pSpatialFileter, false);
            IFeature pFeatLn;

            while ((pFeatLn = pFeatCurLn.NextFeature()) != null)
            {
                if (pFeatLn.get_Value(idxLn) == null || pFeatLn.get_Value(idxLn) == DBNull.Value) continue;

                IPolyline pLn = pFeatLn.ShapeCopy as IPolyline;

                IGeometry pGeometry = pTop.Intersect(pLn, esriGeometryDimension.esriGeometry0Dimension);
                if (pGeometry == null || pGeometry.IsEmpty) continue;

                IPoint pPntRst = (pGeometry as IGeometryCollection).get_Geometry(0) as IPoint;

                #region 找到离高程点两边最近的等高线
                //纵向
                if (Math.Abs(pPoint.X - pPntRst.X) < 0.001)
                {
                    if (pPntRst.Y > pPoint.Y)
                    {
                        if ((idmore == -1) || (pPntRst.Y < more))
                        {
                            idmore = pFeatLn.OID;
                            more = pPntRst.Y;
                        }
                    }
                    else
                    {
                        if ((idless == -1) || (pPntRst.Y > less))
                        {
                            idless = pFeatLn.OID;
                            less = pPntRst.Y;
                        }
                    }
                }
                //横向
                else if (Math.Abs(pPoint.Y - pPntRst.Y) < 0.001)
                {
                    if (pPntRst.X > pPoint.X)
                    {
                        if ((idmore == -1) || (pPntRst.X < more))
                        {
                            idmore = pFeatLn.OID;
                            more = pPntRst.X;
                        }
                    }
                    else
                    {
                        if ((idless == -1) || (pPntRst.X > less))
                        {
                            idless = pFeatLn.OID;
                            less = pPntRst.X;
                        }
                    }
                }
                #endregion
            }

            DataCheckUtility.ReleaseComObject(pFeatCurLn);

            if (idmore == -1 || idless == -1)
            {
                RecordListHelper.AddRecordItem(errType, pFeatLyrPt, pFeatLyrLn, pFeatPt, null, pPoint, "该处程序已无法判断，请您人工核查。");
                return false;
            }
            
            double elePt ;
            if (StringHelper.CanConvert2Double(pFeatPt.get_Value(idxPt)))
                elePt = Double.Parse(StringHelper.ConvertWRTNull(pFeatPt.get_Value(idxPt)));
            else
            {
                LogHelper.WriteLog("高程点ID[" + pFeatPt.OID + "]的高程字段不能转换成数字！");
                return true;
            }

            IFeature pFeatLn1 = pFeatClsLn.GetFeature(idmore);
            double eleLn1;

            if (StringHelper.CanConvert2Double(pFeatLn1.get_Value(idxLn)))
                eleLn1 = Double.Parse(StringHelper.ConvertWRTNull(pFeatLn1.get_Value(idxLn)));
            else
            {
                LogHelper.WriteLog("等高线ID[" + pFeatLn1.OID + "]的高程字段不能转换成数字！");
                return true;
            }

            IFeature pFeatLn2 = pFeatClsLn.GetFeature(idless);
            double eleLn2;
            if (StringHelper.CanConvert2Double(pFeatLn2.get_Value(idxLn)))
                eleLn2 = Double.Parse(StringHelper.ConvertWRTNull(pFeatLn2.get_Value(idxLn)));
            else
            {
                LogHelper.WriteLog("等高线ID[" + pFeatLn1.OID + "]的高程字段不能转换成数字！");
                return true;
            }

            if ((eleLn1 <= elePt && elePt <= eleLn2) || (eleLn1 >= elePt && elePt >= eleLn2)) return true;

            //用"["和"]"之后，序列化不回来
            string remark = "线ID(" + idmore + ")高程：" + eleLn1 + "；点ID(" + pFeatPt.OID + ")高程：" + elePt + "；线ID(" + idless + ")高程：" + eleLn2;
            //string remark = "线ID[" + idmore + "]高程：" + eleLn1 + "；点ID[" + pFeatPt.OID + "]高程：" + elePt + "；线ID[" + idless + "]高程：" + eleLn2;
            RecordListHelper.AddRecordItem(errType, pFeatLyrPt, pFeatLyrLn, pFeatPt, null, pPoint, remark);
            errCount++;

            return true;
          
        }
    }
}
